/**
 * @author Austin Andrews (Templarian)
 * @authorurl http://templarian.com
 * @framework DD Framework
 * @licence MIT License
 * @licenceurl http://ddframework.googlecode.com/svn/trunk/license.txt
 * @overview Parse XML into a JSON styled object.
 */
dd.xml({
    /**
     * Use as a function or to process XML
     * @namespace dd.xml
     * @property
     *  Access XML inscope off this module
     * @function
     *  Parse dynamic XML files
     *  @param obj {object} An object with callbacks and settings
     *  ```javascript
     *  dd.xml({
     *      url:"file.xml",
     *      // Required: Callback for successful parse and download.
     *      success:function()
     *      {
     *          // this.xml.node[0]
     *      },
     *      // Required: Callback for failed parse or download.
     *      failure:function()
     *      {
     *          
     *      }
     *  });
     *  ```
     * @function
     *  Parse string for XML
     *  @param xml {string} XML with or without <?xml >
     *  return xml object
     */
    func:function(o, s)
    {
        if(typeof(o) == "string")
        {
            if(o == "")
            {
                return false;
            }
            try {
                return this.xml._xml.parse(o);
            }
            catch(e)
            {
                return false;
            }
        }
        else
        {
            var vs = {
                scope: this,
                validate: o.validate || function(){return true;},
                success: o.success,
                failure: o.failure || function()
                {
                    dd.log("XML failed to parse or success event failed:\n" + this.text, dd.log.error);
                }
            };
            if(typeof(s) != "undefined")
            {
                for(var i in s)
                {
                    vs[i] = s[i];
                }
            }
            return dd.http({
                url: o.url,
                get: o.get,
                post: o.post,
                success: function()
                {
                    var f = true;
                    try
                    {
                        this.xml = this.scope._xml.parse(this.text);
                        if(this.validate.call(this))
                        {
                            this.success.call(this);
                            f = false;
                        }
                    }
                    catch(e)
                    {
                        dd.log(e.fileName.match(/([^\/]*)$/)[1] + " ("
                            + e.lineNumber + "): " + e.message, dd.log.error);
                    }
                    if(f)
                    {
                        this.xml = {};
                        this.failure.call(this);
                    }
                    
                },
                failure:function()
                {
                    if("failure" in dd.xml._xml)
                    {
                        this.xml = {};
                        this.failure.call(this);
                    }
                }
            }, vs);
        }
    },
    _xml:{
        file:'',
        parse:function(text)
        {
            text = text.replace(/\w+:\w+=".*?"|<!--[\s\S]*?-->|<\?xml-[^>]+>/gm, "");
            if(window.DOMParser)
            {
                parser = new DOMParser();
                doc = parser.parseFromString(text, "text/xml");
            }
            else
            {
                var temp = new ActiveXObject("Microsoft.XMLDOM");
                temp.async="false";
                temp.loadXML(text);
                var doc = {};
                doc.childNodes = [];
                if(temp.childNodes[1] == null)
                {
                    doc.childNodes[0] = temp.childNodes[0];
                }
                else
                {
                    doc.childNodes[0] = temp.childNodes[1];
                }
            }
            return this.parser.call(this, {
                doc:doc,
                index:0
            });
        },
        parser:function(o)
        {
            var doc = o.doc.childNodes[o.index];
            var xml = {};
            xml.children = [];
            var p = {};
            if(doc.childNodes.length > 0)
            {
                for(var i = 0; i < doc.childNodes.length; i++)
                {
                    if(!(/^[ \t\r\n]+$/.test(doc.childNodes[i].nodeValue)))
                    {
                        if(doc.childNodes[i].attributes != null)
                        {
                            if(xml[doc.childNodes[i].tagName] == undefined)
                            {
                                xml[doc.childNodes[i].tagName] = [];
                            }
                            var n = doc.childNodes[i].tagName;
                            var pn = doc.tagName;
                            p[n] = isNaN(p[n]) ? 0 : p[n] + 1;
                            xml.children.push({tagName:n, parentTagName:pn, index:p[n]});
                            var d = xml[n].push(dd.xml._xml.parser.call(this, {
                                doc:doc,
                                index:i
                            }));
                            xml.attributes = [];
                            xml.tagName = n;
                            xml.parentTagName = pn;
                            xml.setAttribute = function(name, value)
                            {
                                this.attributes[name] = value;
                            };
                            xml.getAttribute = function(name)
                            {
                                return this.attributes[name];
                            };
                            for(var x = 0; x < doc.attributes.length; x++)
                            {
                                var v = doc.attributes[x].nodeValue;
                                xml.setAttribute(doc.attributes[x].nodeName, isNaN(v) ? v : Number(v));
                            }
                        }
                        else
                        {
                            xml = {
                                children:[],
                                innerText:doc.childNodes[i].nodeValue == undefined ? null : doc.childNodes[i].nodeValue,
                                attributes:[],
                                tagName:doc.childNodes[i].tagName,
                                setAttribute:function(name, value)
                                {
                                    this.attributes[name] = value;
                                },
                                getAttribute:function(name)
                                {
                                    return this.attributes[name];
                                }
                            };
                            for(var x = 0; x < doc.attributes.length; x++)
                            {
                                var v = doc.attributes[x].nodeValue;
                                xml.setAttribute(doc.attributes[x].nodeName, isNaN(v) ? v : Number(v));
                            }
                        }
                    }
                }
            }
            else
            {
                xml = {
                    children:[],
                    innerText:"",
                    attributes:[],
                    setAttribute:function(name, value)
                    {
                        this.attributes[name] = value;
                    },
                    getAttribute:function(name)
                    {
                        return this.attributes[name];
                    }
                };
                for(var x = 0; x < doc.attributes.length; x++)
                {
                    var v = doc.attributes[x].nodeValue;
                    xml.setAttribute(doc.attributes[x].nodeName, isNaN(v) ? v : Number(v));
                }
            }
            return xml;
        }
    }
});